4.战斗逻辑
战斗逻辑可以说是我们游戏核心中的核心了。实现起来也不是很复杂,这里先交待一下思路。
战斗,无非就是战场上随从之间和玩家英雄之前的属性数据的一些结算而已。我的鳄鱼攻击你的鱼人宝宝,那么我的鳄鱼生命值就减去你的鱼人宝宝随从的攻击力,如果为负,说明鳄鱼人宝宝的攻击力大于我们的鳄鱼随从的攻击力,那么鳄鱼就会阵亡。鱼人宝宝同样要做相同的结算,如果鱼人宝宝的生命值大于鳄鱼的攻击力,那么承受这次攻击之后,鱼人宝宝并不会阵亡,但要将生命值进行更新,也就是鱼人宝宝的最新生命值应该是之前生命值减去鳄鱼的攻击力才对。如果攻击的目标是英雄,直接用英雄的血量去减去攻击者的攻击力。当英雄的血量降到1点以下时(不包含1点),那么英雄也就阵亡,游戏的胜负也就分出来了。
ok,了解规则之后,我们看看当前游戏中的战斗逻辑的触发点。
- 1、当我们攻击敌方的战场随从时,会触发战斗结算
- 2、当我们攻击敌方英雄本体时,会触发战斗结算
- 3、当敌人攻击我们的战场随从时,会触发战斗结算
- 4、当敌人攻击我们的英雄本体时,会触发战斗结算
ok,弄明白这四种结算触发点之后,我们就可以开始来写逻辑了。
首先要做的第一件事,就是要把战场上随从的状态表示出来。战场上的随从有两种状态,休眠状态和激活状态。被召唤上场的随从第一回合是无法进行攻击的,需要用休眠状态来表示,在第二个回合,上一回合被召唤出来处于休眠状态的随从就可以发动攻击了,在他攻击完之后,又用进入休眠状态,直到下一个回合解除休眠。
来看下我们对Fighter.js类的修改:
1 |
|
这里我们在buildFighter函数中新加了一个attack_tag图片,并且暂时将其隐藏了起来。这个图标是为了我们后面选择战斗随从而作标记的。并且我们将fightBg的默认alpha设为了0.7,这样,当我们的随从被第一次召唤出来的时候,就会以半透明显示了。只有当随从进入激活状态,也就是半透明不为1时,才能进行相关操作。
后面的awakeFighter是在每个回合开始之前唤醒我们的随从的方法。
最后在UIManager中激活我们的睡眠随从。
UIManager.js:
1 |
|
写到做到这里,我们开始要写战斗随从之间的战斗了。首先要把我方的随从激活,我们选择了哪个随从,那么拿到该随从的资料,然后再选择敌人的随从,两者作数据的相关结算。
看下我们Fighter.js类:
1 |
|
这里我们引入了DataManager.js,因为我们的很多的数据处理需要在这个对象中进行。
1 | heroFighterChoise:null, // 战斗随从的选择 |
同时,也在DataManager中加入这个玩家随从选择的管理对象。
由于我们是无法操纵敌人的战场随从的,而且在点击敌人的随从之后所触发的是战斗的结算。这里我们就需要在EnemyFighter.js类中,去重写choiceFighter方法。
打开EnemyFighter.js:
1 |
|
做完随从之间的战斗逻辑,还有一个对英雄造成伤害的逻辑结算。
打开我们的EnemyHead.js类:
1 |
|
如图,基本的玩家战斗逻辑就搞定了。不过接下来我们还有几件事情要做。
- 费用的管理
- AI的随从操作
- 补牌逻辑
- 剩余卡牌的展示
- 其他的完善工作
5.水晶的管理
前面我们已经完成了基本的一些战斗逻辑,但是如果玩家可以一次性把所有的手牌打光,这明显是不合理的。在炉石的游戏中,每个随从都是和水晶费用相关联的,而之前我们已经声明好了Fee.js这个类及其子类,接下来我们要使他发挥其真正的作用。
打开我们的Fee.js:
1 |
|
这里我们所做的改动不多,只是将初始化的显示数值由之前的”9/9”改成了”1/1”。打开DataManager.js,我们要加几个数据字段进去:
1 |
|
打开UIManager.js:
1 |
|
水晶的逻辑主要是在出牌按钮之中,只有符合要求的卡牌才能被成功打出,水晶的更新主要是在回合结束的按钮之中完成,当敌人回合结束之后,玩家的水晶会被重置并上限加一,玩家的回合结束,那么敌人的水晶也会执行同样的逻辑。
水晶的控制也算是完成了。但是到这里我们发现,我们的电脑AI虽然会出牌了,随从却并没有采取果任何行动,像个木头人一样,这怎么行,这样的对战也是太无趣了。这里我们来开始写一点简单的AI进攻的逻辑。
打开AI.js:
1 |
|
这里的AI逻辑很简单,首先对场上的随从的场攻进行一个判断,如果AI方的场攻大于玩家方的,那么AI就可以肆无忌惮的攻击玩家的英雄本体了,如果小于,则需要攻击玩家的随从来降低场攻,不过对随从的选择还是比较简单的,只是选择了战场随从的第一个来作为目标。如果你希望AI看起来更加聪明一点可以计算下玩家场上攻击力最高的随从,如果最高的攻击力随从死掉之后,再计算下双方的场攻,然后重复上面的逻辑。
最后放上玩家的补牌逻辑和电脑的补牌逻辑,玩家:打开HandCard.js加入addCard这个方法。
1 |
|
然后电脑的AI的补牌逻辑我们写在EnemyHandCard类之中:
1 |
|
最后记得在UIManager中去执行这两个方法,让玩家在出牌之前记得先补充一张手牌:
1 |
|
到这里,游戏的主要逻辑就走完了。不过游戏并没有完成。我们还有一些收尾工作要做。
比如我们要限制场上的随从的数量,要限制手牌的数量,牌库里的卡牌用完后的处理,还有当玩家或电脑AI的生命值降为0时游戏结束的判定。
先看下对场上随从数量的限制,打开UIManager.js,在其中的setShotCardButton方法中加入:
1 |
|
同样的,在AI.js类中也找到AI的出牌方法shotCard,加上:
1 |
|
然后补牌逻辑的判定和上述的方法类似,只要判断手牌是否大于8张,如果大于或者等于8张,那么抽到的卡牌就无法再加入到手牌之中,也就是会被摧毁掉。
打开HandCard.js类,在addCard方法中加上:
1 |
|
EnemyHandCard因为重写了addCard方法,所以我们在EnemyHandCard中也这样做一次就可以了。
1 |
|
这样,一些基本卡组的限制就做完了。别忘了,我们还剩一件事情没做。那就试关于游戏胜负的结算。
我们新建一个场景,ResultScene.js:
1 |
|
然后在我们main.js中加入这个场景:
1 |
|
最后在结算中加入我们的触发函数,打开EnemnyHead.js:
1 |
|
AI.js:
1 |
|
到这里游戏的主要的逻辑都已经实现完毕了。现在完全可以和电脑来一局纯靠人品的战斗~
六.小结
教程在这里就告了一个段落了。但是不意味着游戏就已经结束了。还有一个简单的小功能,剩余卡牌的提示功能这里我就不再做了,如果对前面的文章有认真研究的同学,应该可以自己把这个功能开发出来。
关于拓展:
游戏的各个组件基本都是封装成了类的,游戏的主要逻辑是写在UIManager.js中的各个按钮事件的触发之中,所有驱动游戏进程的数据在DataManager.js中。如果你要把游戏拓展得比现有功能更加强大,更加完美那也是完全可行的。
最后,感谢各位的收看,整个项目托管地址在这里。